package edu.kit.csl.pisa.datatypes;

/*
This file is part of the PISA Alignment Tool.

Copyright (C) 2013
Karlsruhe Institute of Technology
Cognitive Systems Lab (CSL)
Felix Stahlberg

PISA is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PISA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PISA. If not, see <http://www.gnu.org/licenses/>.
*/

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import edu.kit.csl.pisa.io.Logger;
import edu.kit.csl.pisa.ui.Configuration;

/**
 * A corpus is modeled as set of SentencePair instances. Note that thus we add
 * a set of alignments to each pair, so we use the term "corpus" to address not 
 * only the sentence pairs in the database, but also their current n-best
 * alignments.
 * 
 * @see SentencePair
 */
public class Corpus implements Iterable<SentencePair> {
	/*
	 * Stores the set of SentencePairs
	 */
	private List<SentencePair> database;
	
	private int maxSrcSenLen, maxTrgtSenLen;
	private boolean srcSenLenChecking, trgtSenLenChecking;
	
	private static final String META_INFO_PATTERN = 
			"# Sentence pair (%s) source length %d target words %d target "
			+ "length %d alignment score : %e\n";
	
	/**
	 * Sole constructor. Creates an empty corpus.
	 */
	public Corpus() {
		database = new LinkedList<SentencePair>();
		maxSrcSenLen = Configuration.getSingleton()
				.getInteger("maxSrcSenLen");
		maxTrgtSenLen = Configuration.getSingleton()
				.getInteger("maxTrgtSenLen");
		srcSenLenChecking = (maxSrcSenLen > 0);
		trgtSenLenChecking = (maxTrgtSenLen > 0);
	}
	
	/**
	 * Add a new sentence pair to the corpus.
	 * 
	 * @param sentencePair the sentence pair to add
	 * @return {@code true} if the pair was added, {@code false} if some
	 * 		checks (i.e. length checks) failed and the pair was discarded
	 */
	public boolean add(SentencePair sentencePair) {
		final int srcSenLen = sentencePair.getSourceSentence().getLength();
		final int trgtSenLen = sentencePair.getTargetSentence().getLength();
		if (srcSenLen > maxSrcSenLen) {
			if (srcSenLenChecking) {
				Logger.getSingleton().debug("Source sentence too long in \n"
						+ sentencePair);
				return false;
			}
			maxSrcSenLen = srcSenLen;
			Configuration.getSingleton().set("maxSrcSenLen", maxSrcSenLen);
		}
		if (trgtSenLen > maxTrgtSenLen) {
			if (trgtSenLenChecking) {
				Logger.getSingleton().debug("Target sentence too long in \n"
						+ sentencePair);
				return false;
			}
			maxTrgtSenLen = trgtSenLen;
			Configuration.getSingleton().set("maxTrgtSenLen", maxTrgtSenLen);
		}
		database.add(sentencePair);
		return true;
	}

	@Override
	public Iterator<SentencePair> iterator() {
		return database.iterator();
	}
	
	/**
	 * Get the number of sentence pairs in the corpus.
	 * 
	 * @return the number of sentence pairs
	 */
	public int size() {
		return database.size();
	}

	/**
	 * Dumps the corpus into a file. The generated file has a format similar
	 * to GIZA++'s *.A3 files, but extended with the more complex alignment
	 * definition.
	 * 
	 * @param fileName the name of the file in which should be written
	 */
	public void dumpToFilesystem(String fileName) {
		try {
			FileWriter fs = new FileWriter(fileName);
			BufferedWriter out = new BufferedWriter(fs);
			for (SentencePair pair : database) {
				SentenceAlignment a = pair.getViterbiAlignment();
				if (a == null) {
					out.write("# Sentence pair (" + pair.getId() + ") has no "
							+ "feasible alignment.\n");
				} else {
					out.write(String.format(META_INFO_PATTERN,
							pair.getId(),
							pair.getSourceSentence().getLength(),
							a.getAlignment().countTargetWords(),
							a.getAlignment().countTargetPhonemes(),
							Math.exp(pair.getViterbiScore())));
					out.write(a.toString() + "\n");
				}
			}
			out.close();
		} catch (IOException e) {
			Logger.getSingleton().error("Error while dumping corpus to "
					+ fileName + ": " + e.getMessage());
		}
	}
}
